﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using CommandLine;

namespace PackToKindle
{
    class Program
    {
        static void Main(string[] args)
        {
            // Read command line arguments.
            var arguments = new CommandLineArguments();
            var parser = new CommandLineParser();
            var stringWriter = new StringWriter();
            if (!parser.ParseArguments(args, arguments, stringWriter))
            {
                Console.Write(stringWriter);
                return;
            }

            // If we have device and user select not to convert books - send to Kindle directly.
            // if (!arguments.Convert && _KindleDevice != null)
            //    _SendDirectlyToKindle(arguments, _KindleDevice);
            // Otherwise - send by mail.
            else
                _SendToKindleByMail(arguments, Settings.ApplicationSettings);
        }

        private static void _SendDirectlyToKindle(CommandLineArguments arguments, IKindle kindleDevice)
        {
            foreach (var book in _GetFileList(arguments.Folder))
                kindleDevice.CopyBook(book);
        }

        /// <summary>
        /// Process books from folder.
        /// </summary>
        /// <param name="arguments"></param>
        /// <param name="settings"></param>
        private static void _SendToKindleByMail(CommandLineArguments arguments, Settings settings)
        {
            bool convert = arguments.Convert;

            var mailer = new Mailer(settings.MailSettings);

            // Compute max size of the mail attaches.
            var maxAttachSize = settings.MailSettings.MaxAttachSizeMB * BYTES_IN_MEGABYTE;
            long maxZipSize = Math.Min(maxAttachSize, MAX_SERIVCE_INPUT_FILE_SIZE_MB);

            // Create file storage.
            var storage = arguments.Zip ? (IBookStorage)new Zipper() : (IBookStorage)new SimpleStorage();

            foreach (var file in _GetFileList(arguments.Folder))
            {
                // If adding new file we will exceed size limits - pack and send files which were added to zipper.
                if (storage.CurrentSize + file.Length > maxZipSize)
                    _ZipAndSend(convert, mailer, storage);

                storage.AddFile(file);
            }

            _ZipAndSend(convert, mailer, storage);
        }

        private static void _ZipAndSend(bool convert, Mailer mailer, IBookStorage storage)
        {
            var zipedFiles = storage.Zip();
            mailer.SendMail(convert, zipedFiles);

            // Delete zip files.
            foreach (var file in zipedFiles)
                File.Delete(file);
        }

        private static IEnumerable<FileInfo> _GetFileList(string folderToSend)
        {
            var allowedExtensions = new HashSet<string>(ALLOWED_EXTENSIONS, StringComparer.OrdinalIgnoreCase);

            DirectoryInfo dirInfo = new DirectoryInfo(folderToSend);
            return dirInfo.EnumerateFiles().
                Where(f => allowedExtensions.Contains(f.Extension)).
                OrderBy(info => info.Length);
        }

        #region private constants

        /// <summary>
        /// Extensions allowed by Amazon service. 
        /// </summary>
        private readonly static string[] ALLOWED_EXTENSIONS = new string[]{
            ".DOC", ".DOCX",".HTML", ".HTM",".RTF", ".JPEG", ".JPG" ,".MOBI", ".AZW", ".GIF", ".PNG", ".BMP", ".PDF"};

        private const long BYTES_IN_MEGABYTE = 1024 * 1024;

        private static IKindle _KindleDevice
        {
            get
            {
                if (!_hasBeenSearched)
                {
                    _kindle = DeviceDetector.GetKindle();
                    _hasBeenSearched = true;
                }

                return _kindle;
            }
        }

        private const long MAX_SERIVCE_INPUT_FILE_SIZE_MB = 50 * BYTES_IN_MEGABYTE;

        private static bool _hasBeenSearched;
        private static IKindle _kindle;

        #endregion
    }
}
